﻿/**
*    @file:    filestoragecontroller.cpp
*    @brief:
*    @author:  sanshi522@163.com
*    @date:    2025-05-26  17:23
*/
#include "filestoragecontroller.h"

#include <QDateTime>
#include <QDir>
#include <QFileInfo>
#include <QGlobalConfig>
#include <QJsonDocument>
#include <QJsonObject>
#include <QStack>
#include <qdirutils.h>
#include <responesutils.h>

FileStorageController::FileStorageController(QObject *parent)
    : HttpRequestHandler(parent)
{
}

FileStorageController::~FileStorageController()
{
}

void FileStorageController::service(HttpRequest &request, HttpResponse &response)
{
    QString method = getRequestPath(request, 3);
    if (method.isEmpty())
    {
        return this->returnError(response);
    }
    QByteArray responseMsg;
    QString methodType = request.getMethod();
    if (methodType == "GET")
    {
        if (method == "list")
        {
            return list(request, response);
        }

        if (method == "info")
        {
            return info(request, response);
        }

        if (method == "download")
        {
            return download(request, response);
        }
    }
    if (methodType == "POST")
    {
        if (method == "read")
        {
            return read(request, response);
        }
        if (method == "write")
        {
            return write(request, response);
        }
    }
    if (methodType == "DELETE")
    {
        if (method == "delete")
        {
            return deleteFile(request, response);
        }
    }
}

void FileStorageController::list(HttpRequest &request, HttpResponse &response)
{
    QString path = request.getParameter("path");
    QJsonObject resJsonObject;
    QString rootPath = QGlobalConfig::getInstance().read("storage", "rootPath", "D:\\FileStorage").toString();
    QString dirPath = QDir::cleanPath(QString("%1/%2").arg(rootPath, path));
    ; // 使用 QDir 拼接路径更安全

    QDir dir(dirPath);

    if (dir.exists())
    {
        resJsonObject["status"] = 0;
        resJsonObject["statusText"] = "成功";

        QJsonArray items;

        // 获取当前目录下的所有条目（文件和文件夹）
        QFileInfoList entryList = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot);

        for (const QFileInfo &info : entryList)
        {
            QJsonObject item;
            QString itemName = info.fileName();
            QString absoluteFilePath = info.absoluteFilePath();

            // 计算相对路径：去掉根目录前缀
            // 计算相对路径（使用 QDir 提供的函数）
            QString relativePath = QDir(rootPath).relativeFilePath(info.absoluteFilePath());

            item["name"] = itemName;

            if (info.isDir())
            {
                item["type"] = "folder";
                item["size"] = 0; // 文件夹不统计大小
            }
            else
            {
                item["type"] = "file";
                item["size"] = info.size(); // 文件大小
            }

            item["path"] = relativePath;

            items.append(item);
        }

        resJsonObject["items"] = items;
    }
    else
    {
        resJsonObject["status"] = -1;
        resJsonObject["statusText"] = "路径不存在";
    }

    // 返回结果
    response.setStatus(200);
    response.setHeader("Content-Type", "application/json");
    response.write(QJsonDocument(resJsonObject).toJson());
}

qint64 getDirectorySize(const QString &dirPath)
{
    qint64 size = 0;
    QDir dir(dirPath);
    if (!dir.exists())
        return 0;

    QStack<QString> dirs;
    dirs.push(dirPath);

    while (!dirs.isEmpty())
    {
        QString currentDir = dirs.pop();
        QDir d(currentDir);
        for (const QFileInfo &info : d.entryInfoList(QDir::Files))
        {
            size += info.size();
        }
        for (const QFileInfo &info : d.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot))
        {
            dirs.push(info.absoluteFilePath());
        }
    }

    return size;
}

void FileStorageController::info(HttpRequest &request, HttpResponse &response)
{
    QString path = request.getParameter("path");
    QJsonObject resJsonObject;

    if (path.isEmpty())
    {
        resJsonObject["status"] = -1;
        resJsonObject["statusText"] = "路径为空";
        response.setStatus(400);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }

    QString targetPath;
    //判断path是不是绝对路径
    if (QDir::isAbsolutePath(path))
    {
        targetPath = QDir::cleanPath(path);
    }
    else
    {
        QString rootPath = QGlobalConfig::getInstance().read("storage", "rootPath", "D:/FileStorage").toString();
        targetPath = QDir::cleanPath(QString("%1/%2").arg(rootPath, path));
    }

    QFileInfo info(targetPath);

    if (!info.exists())
    {
        resJsonObject["status"] = -2;
        resJsonObject["statusText"] = "路径不存在";
        resJsonObject["path"] = path;
        response.setStatus(404);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }

    resJsonObject["status"] = 0;
    resJsonObject["statusText"] = "成功";
    resJsonObject["name"] = info.fileName();
    resJsonObject["path"] = path;
    resJsonObject["isDir"] = info.isDir();
    resJsonObject["lastModified"] = info.lastModified().toString(Qt::LocalDate);

    if (info.isDir())
    {
        resJsonObject["type"] = "folder";
        resJsonObject["size"] = 0; // 默认不统计文件夹大小
        // 可选：递归统计目录大小（耗性能）
        // resJsonObject["size"] = getDirectorySize(info.absoluteFilePath());
    }
    else
    {
        resJsonObject["type"] = "file";
        resJsonObject["size"] = info.size();
    }

    response.setStatus(200);
    response.setHeader("Content-Type", "application/json");
    response.write(QJsonDocument(resJsonObject).toJson());
}

void FileStorageController::write(HttpRequest &request, HttpResponse &response)
{
    qDebug() << __FUNCTION__;
    QJsonObject resJsonObject;
    // 读取 JSON 数据
    QJsonDocument jsonDoc = QJsonDocument::fromJson(request.getBody());
    if (jsonDoc.isNull() || !jsonDoc.isObject())
    {
        resJsonObject["status"] = -1;
        resJsonObject["statusText"] = "无效的JSON数据";
        response.setStatus(400);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }

    QJsonObject reqObj = jsonDoc.object();

    // 检查必要字段
    if (!reqObj.contains("path") || !reqObj.contains("data"))
    {
        resJsonObject["status"] = -2;
        resJsonObject["statusText"] = "缺少必要参数（path 或 data）";
        response.setStatus(400);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }

    QString path = reqObj["path"].toString();
    QString base64Data = reqObj["data"].toString();
    qint64 offset = reqObj.value("offset").toVariant().toLongLong(); // 如果没有 offset，默认为 -1

    qDebug() << __FUNCTION__ << path << base64Data.size() << offset;
    // 获取根目录并拼接目标路径
    QString targetPath;
    //判断path是不是绝对路径
    if (QDir::isAbsolutePath(path))
    {
        targetPath = QDir::cleanPath(path);
    }
    else
    {
        QString rootPath = QGlobalConfig::getInstance().read("storage", "rootPath", "D:/FileStorage").toString();
        targetPath = QDir::cleanPath(QString("%1/%2").arg(rootPath, path));
    }
    // 创建父目录（如果不存在）
    QFileInfo fileInfo(targetPath);
    QDir dir = fileInfo.dir();
    if (!dir.exists())
    {
        if (!dir.mkpath("."))
        {
            resJsonObject["status"] = -3;
            resJsonObject["statusText"] = "无法创建目标目录";
            resJsonObject["path"] = path;
            response.setStatus(500);
            response.write(QJsonDocument(resJsonObject).toJson());
            return;
        }
    }

    // 解码 Base64 数据
    QByteArray decodedData = QByteArray::fromBase64(base64Data.toUtf8());

    // 校验长度（如果提供了 length 字段）
    qint64 expectedLength = reqObj.value("length").toVariant().toLongLong();
    if (expectedLength > 0 && decodedData.size() != expectedLength)
    {
        resJsonObject["status"] = -4;
        resJsonObject["statusText"] = "数据长度与声明的 length 不符";
        resJsonObject["expected"] = expectedLength;
        resJsonObject["actual"] = decodedData.size();
        response.setStatus(400);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }

    // 打开文件进行写入
    QFile file(targetPath);
    bool openSuccess = false;

    if (offset == 0)
    {
        // 偏移量为0：使用 WriteOnly | Unbuffered 可能更合适
        openSuccess = file.open(QIODevice::WriteOnly | QIODevice::Append); // 覆盖写入
    }
    else
    {
        // 默认追加写入
        openSuccess = file.open(QIODevice::WriteOnly | QIODevice::Append);
    }

    if (openSuccess && offset > 0)
    {
        file.seek(offset);
    }

    qDebug() << __FUNCTION__ << openSuccess << "写入位置" << offset;

    if (!openSuccess)
    {
        resJsonObject["status"] = -5;
        resJsonObject["statusText"] = "无法打开文件进行写入";
        resJsonObject["path"] = path;
        response.setStatus(500);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }

    // 写入数据
    qint64 bytesWritten = file.write(decodedData);

    if (bytesWritten != decodedData.size())
    {
        resJsonObject["status"] = -6;
        resJsonObject["statusText"] = "写入数据不完整";
        resJsonObject["written"] = bytesWritten;
        resJsonObject["total"] = decodedData.size();
    }
    else
    {
        resJsonObject["status"] = 0;
        resJsonObject["statusText"] = "写入成功";
        resJsonObject["path"] = path;
        resJsonObject["size"] = file.size();
    }

    file.close();
    response.setStatus(200);
    response.write(QJsonDocument(resJsonObject).toJson());
}

void FileStorageController::read(HttpRequest &request, HttpResponse &response)
{
    QJsonObject resJsonObject;

    // 解析 JSON 数据
    QJsonDocument jsonDoc = QJsonDocument::fromJson(request.getBody());
    if (jsonDoc.isNull() || !jsonDoc.isObject())
    {
        resJsonObject["status"] = -1;
        resJsonObject["statusText"] = "无效的JSON数据";
        response.setStatus(400);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }

    QJsonObject reqObj = jsonDoc.object();

    // 检查必要字段
    if (!reqObj.contains("path"))
    {
        resJsonObject["status"] = -2;
        resJsonObject["statusText"] = "缺少必要参数：path";
        response.setStatus(400);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }

    QString path = reqObj["path"].toString();
    qint64 offset = reqObj.value("offset").toVariant().toLongLong(); // 默认从0开始
    qint64 length = reqObj.value("length").toVariant().toLongLong(); // -1 表示读到结尾

    QString targetPath;
    //判断path是不是绝对路径
    if (QDir::isAbsolutePath(path))
    {
        targetPath = QDir::cleanPath(path);
    }
    else
    {
        QString rootPath = QGlobalConfig::getInstance().read("storage", "rootPath", "D:/FileStorage").toString();
        targetPath = QDir::cleanPath(QString("%1/%2").arg(rootPath, path));
    }

    QFile file(targetPath);
    if (!file.exists())
    {
        resJsonObject["status"] = -3;
        resJsonObject["statusText"] = "文件不存在";
        resJsonObject["path"] = path;
        response.setStatus(404);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }

    if (!file.open(QIODevice::ReadOnly))
    {
        resJsonObject["status"] = -4;
        resJsonObject["statusText"] = "无法打开文件";
        resJsonObject["path"] = path;
        response.setStatus(500);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }

    // 设置偏移
    if (offset > 0)
    {
        if (!file.seek(offset))
        {
            resJsonObject["status"] = -5;
            resJsonObject["statusText"] = "无法设置文件偏移";
            resJsonObject["offset"] = offset;
            resJsonObject["path"] = path;
            file.close();
            response.setStatus(500);
            response.write(QJsonDocument(resJsonObject).toJson());
            return;
        }
    }

    // 读取数据
    QByteArray data;
    if (length > 0)
    {
        data = file.read(length);
    }
    else
    {
        data = file.readAll(); // 读取剩余全部内容
    }

    file.close();

    // Base64 编码
    QString base64Data = QString::fromUtf8(data.toBase64());

    resJsonObject["status"] = 0;
    resJsonObject["statusText"] = "成功";
    resJsonObject["length"] = data.size();
    resJsonObject["data"] = base64Data;

    response.setStatus(200);
    response.write(QJsonDocument(resJsonObject).toJson());
}

void FileStorageController::download(HttpRequest &request, HttpResponse &response)
{
    QJsonObject resJsonObject;
    QString path = request.getParameter("path");
    if (path.isEmpty())
    {
        resJsonObject["status"] = -1;
        resJsonObject["statusText"] = "路径为空";
        response.setStatus(400);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }
    QString targetPath;
    //判断path是不是绝对路径
    if (QDir::isAbsolutePath(path))
    {
        targetPath = QDir::cleanPath(path);
    }
    else
    {
        QString rootPath = QGlobalConfig::getInstance().read("storage", "rootPath", "D:/FileStorage").toString();
        targetPath = QDir::cleanPath(QString("%1/%2").arg(rootPath, path));
    }
    QFileInfo fileInfo(targetPath);
    if (!fileInfo.exists())
    {
        resJsonObject["status"] = -2;
        resJsonObject["statusText"] = "目标不存在";
        resJsonObject["path"] = path;
        response.setStatus(404);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }

    // 打开文件并读取内容到响应体中
    QFile file(targetPath);
    if (file.open(QIODevice::ReadOnly))
    {
        // 设置响应头部信息
        response.setStatus(200, "OK");
        response.setHeader("Content-Type", "application/octet-stream");
        response.setHeader("Content-Disposition", QString("attachment; filename=\"%1\"").arg(fileInfo.fileName()).toUtf8());
        response.setHeader("Content-Length", QString::number(file.size()).toLatin1());

        QByteArray fileData = file.read(1024 * 1024 * 5);
        while (fileData.size() > 0)
        {
            // 将文件数据写入HTTP响应
            response.write(fileData); // 第二个参数表示是否立即刷新缓冲区
            fileData = file.read(1024 * 1024 * 5);
        }
        file.close();
    }
    else
    {
        ResponesUtils::erroResponse(response, "无法打开文件！");
    }
}

void FileStorageController::deleteFile(HttpRequest &request, HttpResponse &response)
{
    QString path = request.getParameter("path");
    QJsonObject resJsonObject;

    if (path.isEmpty())
    {
        resJsonObject["status"] = -1;
        resJsonObject["statusText"] = "路径为空";
        response.setStatus(400);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }

    QString targetPath;
    //判断path是不是绝对路径
    if (QDir::isAbsolutePath(path))
    {
        targetPath = QDir::cleanPath(path);
    }
    else
    {
        QString rootPath = QGlobalConfig::getInstance().read("storage", "rootPath", "D:/FileStorage").toString();
        targetPath = QDir::cleanPath(QString("%1/%2").arg(rootPath, path));
    }

    QFileInfo fileInfo(targetPath);

    if (!fileInfo.exists())
    {
        resJsonObject["status"] = -2;
        resJsonObject["statusText"] = "目标不存在";
        resJsonObject["path"] = path;
        response.setStatus(404);
        response.write(QJsonDocument(resJsonObject).toJson());
        return;
    }

    bool success = false;

    if (fileInfo.isFile())
    {
        // 删除文件
        success = QFile::remove(targetPath);
    }
    else if (fileInfo.isDir())
    {
        // 删除整个目录（递归删除）
        success = QDir().rmdir(targetPath); // 如果目录非空会失败
        if (!success)
        {
            // 如果是非空目录，尝试递归删除
            success = QDir(targetPath).removeRecursively();
        }
    }

    if (success)
    {
        resJsonObject["status"] = 0;
        resJsonObject["statusText"] = "删除成功";
        resJsonObject["path"] = path;
    }
    else
    {
        resJsonObject["status"] = -3;
        resJsonObject["statusText"] = "删除失败";
        resJsonObject["path"] = path;
    }

    response.setStatus(200);
    response.setHeader("Content-Type", "application/json");
    response.write(QJsonDocument(resJsonObject).toJson());
}
